﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using WebBuddy.UriBuddy;
namespace WebBuddy.Ajax
{
    /// <summary>
    /// jQuery-like AJAX calls
    /// </summary>
    public class AjaxBuddy : WebBuddy.Ajax.IAjax
    {

        /// <summary>
        /// Load a remote object using an HTTP GET request
        /// </summary>
        /// <param name="requestUri">The URL to use for the request</param>
        /// <param name="callback">This is the function we will call back when the request is complete</param>
        /// <param name="parameters">A dictionary of query parameters</param>
        /// <param name="state">User-defined state</param>
        /// <typeparam name="TResponseType">The type of data you expect to get back</typeparam>
        public void Get<TResponseType>(
            Uri requestUri,
            Dictionary<String, String> parameters,
            GetResponseCallback<TResponseType> callback,
            Object state)
        {

            Get<TResponseType>(requestUri, parameters, new AjaxOptions<TResponseType>
            {
                Callback = callback,
                State = state
                
            });

        }

        /// <summary>
        /// Load a remote object using an HTTP GET request
        /// </summary>
        /// <param name="requestUri">The URL to use for the request</param>
        /// <param name="parameters">A dictionary of query parameters</param>
        /// <param name="state">User-defined state</param>
        /// <param name="callback">This is the function we will call back when the request is complete</param>
        /// <param name="failure">What to call when we fail</param>
        /// <typeparam name="TResponseType">The type of data you expect to get back</typeparam>
        public void Get<TResponseType>(Uri requestUri, Dictionary<string, string> parameters, GetResponseCallback<TResponseType> callback, AjaxFailure failure, object state)
        {
            Get<TResponseType>(requestUri, parameters, new AjaxOptions<TResponseType>
            {
                Callback = callback,
                State = state,
                FailureCallback = failure
            });
          

        }


        /// <summary>
        /// Make an ajax requesetwith any kind of options you want
        /// </summary>
        /// <param name="requestUri">Uri to make a request to</param>
        /// <param name="parameters">Your parameters</param>
        /// <param name="options">The options when finished</param>
        public void Get<TResponseType>(Uri requestUri, Dictionary<string, string> parameters, AjaxOptions<TResponseType> options)
        {
            Uri uri = BuildUri(requestUri, parameters);
            WebClient client = new WebClient();

            RequestState<TResponseType> stateObject = new RequestState<TResponseType>
            {
                Request = client,
                Options = options

            };
            DoRequest<TResponseType>(uri, stateObject);

        }

        /// <summary>
        /// Build a <see cref="Uri"/>!
        /// </summary>
        /// <param name="requestUri">Your <see cref="Uri"/></param>
        /// <param name="parameters">Your paramenters to add</param>
        /// <returns>A happy new <see cref="Uri"/></returns>
        protected static Uri BuildUri(Uri requestUri, Dictionary<String, String> parameters)
        {
            Uri uri = (parameters == null) ? requestUri : requestUri.AppendQueryValues(parameters);
            return uri;
        }

        /// <summary>
        /// Do a request...
        /// </summary>
        /// <typeparam name="TResponseType">The type of data our user wants</typeparam>
        /// <param name="uri">Where they want us to get it</param>
        /// <param name="stateObject">Our state</param>
        /// <exception cref="ArgumentNullException">Exception thrown when you pass us a <paramref name="stateObject"/> that does not have a valid instance of <see cref="WebClient"/></exception>
        protected static void DoRequest<TResponseType>(Uri uri, RequestState<TResponseType> stateObject)
        {
            if (stateObject.Request == null)
                throw new ArgumentNullException("stateObject", "Must have a valid instance of WebClient");

            stateObject.Request.AllowReadStreamBuffering = true;
            stateObject.Request.OpenReadCompleted += new OpenReadCompletedEventHandler(Request_OpenReadCompleted<TResponseType>);
            stateObject.Request.OpenReadAsync(uri, stateObject);
        }

        private static void Request_OpenReadCompleted<TResponseType>(object sender, OpenReadCompletedEventArgs e)
        {
            RequestState<TResponseType> state = (RequestState<TResponseType>)e.UserState;
            if (e.Error == null)
            {
                HandleSuccess<TResponseType>(e, state);
            }
            else
            {
                HandleFailure<TResponseType>(e, state);

            }
        }


        /// <summary>
        /// Life is good, lets let our caller know about it!
        /// </summary>
        /// <typeparam name="TResponseType">What kind of stuff they want</typeparam>
        /// <param name="e">Our happy completion event args</param>
        /// <param name="state">Our state</param>
        protected  static void HandleSuccess<TResponseType>(OpenReadCompletedEventArgs e, RequestState<TResponseType> state)
        {
            TResponseType result = e.Result.FromJSON<TResponseType>(typeof(TResponseType));
            state.Options.Callback(result, state.Options.State);
        }

        /// <summary>
        /// Life sucks, lets let our caller know, but only if they insist!
        /// </summary>
        /// <typeparam name="TResponseType">What kind of stuff they want</typeparam>
        /// <param name="e">Our sad completion event arguments</param>
        /// <param name="state">Our state</param>
        protected static void HandleFailure<TResponseType>(OpenReadCompletedEventArgs e, RequestState<TResponseType> state)
        {
            if (state.Options.FailureCallback != null)
            {
                state.Options.FailureCallback(e.Error, state.Options.State);
            }
        }



      
    }
}
